package com.qms.qep.service.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.text.StringEscapeUtils;
import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.docx4j.Docx4J;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.xhtmlrenderer.pdf.ITextRenderer;

import com.lowagie.text.DocumentException;
import com.qms.common.core.domain.AjaxResult;
import com.qms.common.utils.DateUtils;
import com.qms.common.utils.StringUtils;
import com.qms.common.utils.file.FileUtils;
import com.qms.common.utils.file.FileUploadUtils;
import com.qms.common.config.RuoYiConfig;
import com.qms.qep.domain.CertificateTemplate;
import com.qms.qep.domain.TemplateVariable;
import com.qms.qep.mapper.CertificateTemplateMapper;
import com.qms.qep.mapper.TemplateVariableMapper;
import com.qms.qep.service.ICertificateTemplateService;
import org.apache.commons.io.IOUtils;

/**
 * 证书模板服务实现
 */
@Service
public class CertificateTemplateServiceImpl implements ICertificateTemplateService {
    
    private static final Logger log = LoggerFactory.getLogger(CertificateTemplateServiceImpl.class);
    
    @Autowired
    private CertificateTemplateMapper templateMapper;
    
    @Autowired
    private TemplateVariableMapper variableMapper;
    
    @Value("${qms.certificate.template-path:/certificate/template/}")
    private String templatePath;

    /**
     * 查询证书模板列表
     */
    @Override
    public List<CertificateTemplate> selectCertificateTemplateList(CertificateTemplate template) {
        return templateMapper.selectCertificateTemplateList(template);
    }

    /**
     * 查询证书模板详细信息
     */
    @Override
    public CertificateTemplate selectCertificateTemplateById(Long id) {
        return templateMapper.selectCertificateTemplateById(id);
    }

    /**
     * 新增证书模板
     */
    @Override
    public int insertCertificateTemplate(CertificateTemplate template) {
        template.setCreateTime(DateUtils.getNowDate());
        // 设置默认值
        if (StringUtils.isEmpty(template.getStatus())) {
            template.setStatus("启用");
        }
        if (StringUtils.isEmpty(template.getDelFlag())) {
            template.setDelFlag("0");
        }
        if (template.getVersion() == null) {
            template.setVersion(1);
        }
        if (StringUtils.isEmpty(template.getTemplateFormat())) {
            template.setTemplateFormat("HTML");
        }
        if (StringUtils.isEmpty(template.getEditorType())) {
            template.setEditorType("rich");
        }
        return templateMapper.insertCertificateTemplate(template);
    }

    /**
     * 修改证书模板
     */
    @Override
    public int updateCertificateTemplate(CertificateTemplate template) {
        template.setUpdateTime(DateUtils.getNowDate());
        return templateMapper.updateCertificateTemplate(template);
    }

    /**
     * 批量删除证书模板
     */
    @Override
    @Transactional
    public int deleteCertificateTemplateByIds(Long[] ids) {
        // 删除关联的模板变量
        for (Long id : ids) {
            variableMapper.deleteTemplateVariableByTemplateId(id);
        }
        return templateMapper.deleteCertificateTemplateByIds(ids);
    }
    
    /**
     * 上传模板文件
     */
    @Override
    public AjaxResult uploadTemplateFile(MultipartFile file, String name, String type, String remark) {
        if (file == null || file.isEmpty()) {
            return AjaxResult.error("上传文件不能为空");
        }
        
        // 检查文件类型
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".docx")) {
            return AjaxResult.error("只支持Word文档(docx)格式");
        }
    
        // 检查文件大小
        if (file.getSize() > 10 * 1024 * 1024) {
            return AjaxResult.error("文件大小不能超过10MB");
        }
        
        try {
            // 使用RuoYiConfig的Profile路径
            String baseUploadDir = RuoYiConfig.getProfile();
            String templateSubDir = "/certificate_templates/";
            
            // 确保目录存在
            File dir = new File(baseUploadDir + templateSubDir);
            if (!dir.exists()) {
                boolean created = dir.mkdirs();
                if (!created) {
                    log.error("Failed to create directory: " + dir.getAbsolutePath());
                    Path dirPath = Paths.get(baseUploadDir + templateSubDir);
                    Files.createDirectories(dirPath);
                }
            }
            
            log.info("上传目录路径: " + dir.getAbsolutePath());
            
            // 生成唯一文件名
            String uniqueFileName = UUID.randomUUID().toString() + "_" + originalFilename.replaceAll("[^a-zA-Z0-9._-]", "");
            // 保存相对路径，确保一致性
            String relativePath = "certificate_templates/" + uniqueFileName;
            String fullPath = baseUploadDir + templateSubDir + uniqueFileName;
            
            log.info("准备保存文件到: " + fullPath);
            log.info("数据库将保存路径: " + relativePath);
            
            // 使用Files API保存文件
            Path targetPath = Paths.get(fullPath);
            Files.createDirectories(targetPath.getParent());
            Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
            
            log.info("文件保存成功: " + targetPath.toAbsolutePath());
            
            // 保存模板信息到数据库
            CertificateTemplate template = new CertificateTemplate();
            template.setName(StringUtils.isEmpty(name) ? originalFilename.replace(".docx", "") : name);
            template.setType(StringUtils.isEmpty(type) ? "通用证书" : type);
            template.setTemplateFormat("DOCX");
            template.setTemplateFileUrl(relativePath); // 存储相对路径
            template.setStatus("启用");
            template.setRemark(remark);
            template.setVersion(1);
            template.setEditorType("rich");
            template.setCreateTime(DateUtils.getNowDate());
            
            int rows = templateMapper.insertCertificateTemplate(template);
            if (rows > 0) {
                return AjaxResult.success("上传成功", template);
            } else {
                // 上传失败，删除已保存的文件
                FileUtils.deleteFile(fullPath);
                return AjaxResult.error("上传失败");
            }
        } catch (IOException e) {
            log.error("上传失败", e);
            return AjaxResult.error("上传失败: " + e.getMessage());
        }
    }
    
    /**
     * 预览模板
     */
    @Override
    public AjaxResult previewTemplate(Long id) {
        CertificateTemplate template = templateMapper.selectCertificateTemplateById(id);
        if (template == null) {
            return AjaxResult.error("模板不存在");
        }
    
        // 根据模板格式返回不同预览内容
        if ("HTML".equals(template.getTemplateFormat())) {
            String content = StringUtils.isNotEmpty(template.getEditorContent()) 
                    ? template.getEditorContent() 
                    : template.getContent();
            return AjaxResult.success("预览成功", content);
        } else if ("DOCX".equals(template.getTemplateFormat())) {
             // 对于DOCX，Controller层已经改为调用 previewDocxAsHtml, 
             // 此处的 previewTemplate(id) 对于DOCX应该返回文件本身供下载或由其他专用逻辑处理
             // 如果前端的preview按钮真的还调用这个，那需要明确是下载还是尝试转HTML
             // 假设此方法现在被用于"下载"或获取原始文件数据
            try {
                if (StringUtils.isEmpty(template.getTemplateFileUrl())) {
                    return AjaxResult.error("模板文件URL未配置");
                }
                String filePath = getUploadDir() + template.getTemplateFileUrl();
                Path path = Paths.get(filePath);
                if (!Files.exists(path)) {
                    return AjaxResult.error("模板文件不存在: " + filePath);
                }
                byte[] data = Files.readAllBytes(path);
                // 返回文件数据，前端可以处理为下载
                return AjaxResult.success("文件获取成功", data); 
            } catch (IOException e) {
                log.error("获取DOCX模板文件失败, ID: {}", id, e);
                return AjaxResult.error("获取模板文件失败: " + e.getMessage());
            }
        } else {
            return AjaxResult.error("不支持的模板格式: " + template.getTemplateFormat());
        }
    }
    
    /**
     * 查询模板变量列表
     */
    @Override
    public List<TemplateVariable> selectTemplateVariables(Long templateId) {
        return variableMapper.selectTemplateVariablesByTemplateId(templateId);
    }
    
    /**
     * 保存模板变量
     */
    @Override
    @Transactional
    public int saveTemplateVariables(List<TemplateVariable> variables) {
        if (variables == null || variables.isEmpty()) {
            return 0;
        }
        
        int rows = 0;
        for (TemplateVariable variable : variables) {
            if (variable.getId() != null) {
                // 更新现有变量
                variable.setUpdateTime(DateUtils.getNowDate());
                rows += variableMapper.updateTemplateVariable(variable);
            } else {
                // 新增变量
                variable.setCreateTime(DateUtils.getNowDate());
                variable.setDelFlag("0");
                rows += variableMapper.insertTemplateVariable(variable);
            }
        }
        return rows;
    }
    
    /**
     * 获取上传目录
     */
    private String getUploadDir() {
        // 获取应用程序根目录
        String appRoot = System.getProperty("user.dir");
        // 创建完整的绝对路径
        String fullPath = appRoot + "/uploads" + (templatePath.startsWith("/") ? templatePath : "/" + templatePath);
        // 确保路径以斜杠结尾
        return fullPath.endsWith("/") ? fullPath : fullPath + "/";
    }
    
    /**
     * 获取Word模板内容
     */
    @Override
    public AjaxResult getWordContent(Long id) {
        CertificateTemplate template = templateMapper.selectCertificateTemplateById(id);
        if (template == null) {
            return AjaxResult.error("模板不存在");
        }
        
        // 只处理DOCX格式的模板
        if (!"DOCX".equals(template.getTemplateFormat())) {
            return AjaxResult.error("该模板不是Word格式");
        }
        
        try {
            String filePath = getUploadDir() + template.getTemplateFileUrl();
            Path path = Paths.get(filePath);
            if (!Files.exists(path)) {
                return AjaxResult.error("模板文件不存在");
            }
            
            // 读取文件内容
            byte[] data = Files.readAllBytes(path);
            
            // 返回Word文件内容
            return AjaxResult.success(data);
        } catch (IOException e) {
            return AjaxResult.error("获取Word内容失败: " + e.getMessage());
        }
    }
    
    /**
     * 保存Word模板内容
     */
    @Override
    @Transactional
    public AjaxResult saveWordContent(CertificateTemplate template) {
        if (template == null || template.getId() == null) {
            return AjaxResult.error("无效的模板信息");
        }
        
        // 获取原模板信息
        CertificateTemplate existingTemplate = templateMapper.selectCertificateTemplateById(template.getId());
        if (existingTemplate == null) {
            return AjaxResult.error("模板不存在");
        }
        
        // 只处理DOCX格式的模板
        if (!"DOCX".equals(existingTemplate.getTemplateFormat())) {
            return AjaxResult.error("该模板不是Word格式");
        }
        
        try {
            // 如果有上传新文件内容
            if (template.getWordContent() != null && template.getWordContent().length > 0) {
                String filePath = getUploadDir() + existingTemplate.getTemplateFileUrl();
                Path path = Paths.get(filePath);
                
                // 备份原文件
                String backupFileName = existingTemplate.getTemplateFileUrl() + ".bak";
                Path backupPath = Paths.get(getUploadDir() + backupFileName);
                if (Files.exists(path)) {
                    Files.copy(path, backupPath, StandardCopyOption.REPLACE_EXISTING);
                }
                
                // 写入新内容
                Files.write(path, template.getWordContent());
                
                // 更新模板信息
                existingTemplate.setUpdateTime(DateUtils.getNowDate());
                existingTemplate.setVersion(existingTemplate.getVersion() + 1);
                existingTemplate.setUpdateBy(template.getUpdateBy());
                
                // 保存到数据库
                int rows = templateMapper.updateCertificateTemplate(existingTemplate);
                if (rows > 0) {
                    return AjaxResult.success("保存成功");
                } else {
                    // 保存失败，恢复备份
                    if (Files.exists(backupPath)) {
                        Files.copy(backupPath, path, StandardCopyOption.REPLACE_EXISTING);
                    }
                    return AjaxResult.error("保存失败");
                }
            } else {
                return AjaxResult.error("未提供Word内容");
            }
        } catch (IOException e) {
            return AjaxResult.error("保存Word内容失败: " + e.getMessage());
        }
    }
    
    /**
     * 导出为PDF
     */
    @Override
    public AjaxResult exportToPdf(Long id, Map<String, Object> variables) {
        CertificateTemplate template = templateMapper.selectCertificateTemplateById(id);
        if (template == null) {
            return AjaxResult.error("模板不存在");
        }
        
        try {
            byte[] pdfBytes;
            
            // 根据模板格式选择不同的处理方式
            if ("HTML".equals(template.getTemplateFormat())) {
                // HTML模板转PDF
                String content = StringUtils.isEmpty(template.getEditorContent()) 
                        ? template.getContent() 
                        : template.getEditorContent();
                
                // 替换变量
                content = replaceVariables(content, variables);
                
                // 转换为PDF
                pdfBytes = convertHtmlToPdf(content);
            } else if ("DOCX".equals(template.getTemplateFormat())) {
                // Word模板转PDF
                String filePath = getUploadDir() + template.getTemplateFileUrl();
                Path path = Paths.get(filePath);
                if (!Files.exists(path)) {
                    return AjaxResult.error("模板文件不存在");
                }
                
                // 读取Word文件并替换变量
                byte[] wordBytes = Files.readAllBytes(path);
                byte[] processedWordBytes = processWordTemplate(wordBytes, variables);
                
                // 转换为PDF
                pdfBytes = convertDocxToPdf(processedWordBytes);
            } else {
                return AjaxResult.error("不支持的模板格式");
            }
            
            return AjaxResult.success("导出成功", pdfBytes);
        } catch (Exception e) {
            log.error("PDF导出失败", e);
            return AjaxResult.error("PDF导出失败: " + e.getMessage());
        }
    }
    
    /**
     * 处理Word模板并替换变量
     */
    private byte[] processWordTemplate(byte[] wordBytes, Map<String, Object> variables) throws IOException {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(wordBytes);
             XWPFDocument document = new XWPFDocument(bis);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            
            // 替换文本中的变量
            document.getParagraphs().forEach(paragraph -> {
                String text = paragraph.getText();
                if (text != null && text.contains("${")) {
                    for (Map.Entry<String, Object> entry : variables.entrySet()) {
                        String key = "${" + entry.getKey() + "}";
                        String value = entry.getValue() == null ? "" : entry.getValue().toString();
                        text = text.replace(key, value);
                    }
                    
                    // 更新段落文本
                    paragraph.getRuns().forEach(run -> run.setText("", 0));
                    paragraph.createRun().setText(text);
                }
            });
            
            // 替换表格中的变量
            document.getTables().forEach(table -> {
                table.getRows().forEach(row -> {
                    row.getTableCells().forEach(cell -> {
                        cell.getParagraphs().forEach(paragraph -> {
                            String text = paragraph.getText();
                            if (text != null && text.contains("${")) {
                                for (Map.Entry<String, Object> entry : variables.entrySet()) {
                                    String key = "${" + entry.getKey() + "}";
                                    String value = entry.getValue() == null ? "" : entry.getValue().toString();
                                    text = text.replace(key, value);
                                }
                                
                                // 更新单元格文本
                                paragraph.getRuns().forEach(run -> run.setText("", 0));
                                paragraph.createRun().setText(text);
                            }
                        });
                    });
                });
            });
            
            // 保存修改后的文档
            document.write(bos);
            return bos.toByteArray();
        }
    }
    
    /**
     * 替换HTML中的变量
     */
    private String replaceVariables(String content, Map<String, Object> variables) {
        if (content == null || variables == null || variables.isEmpty()) {
            return content;
        }
        
        String result = content;
        
        // 使用正则表达式查找${variable}形式的变量
        Pattern pattern = Pattern.compile("\\$\\{([^}]+)\\}");
        Matcher matcher = pattern.matcher(content);
        
        // 创建StringBuffer用于构建结果
        StringBuffer sb = new StringBuffer();
        
        // 遍历所有匹配项
        while (matcher.find()) {
            String varName = matcher.group(1);
            Object value = variables.get(varName);
            String replacement = (value != null) ? value.toString() : "";
            
            // 转义替换字符串中的特殊字符
            replacement = Matcher.quoteReplacement(replacement);
            
            // 将匹配项替换为变量值
            matcher.appendReplacement(sb, replacement);
        }
        
        // 添加剩余内容
        matcher.appendTail(sb);
        
        return sb.toString();
    }
    
    /**
     * 将HTML转换为PDF
     */
    private byte[] convertHtmlToPdf(String htmlContent) throws IOException, DocumentException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            // 添加HTML头尾
            String fullHtml = "<!DOCTYPE html><html><head><meta charset='UTF-8'></head><body>" + htmlContent + "</body></html>";
            
            // 使用Flying Saucer将HTML转换为PDF
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(fullHtml);
            renderer.layout();
            renderer.createPDF(baos);
            
            return baos.toByteArray();
        }
    }
    
    /**
     * 将DOCX转换为PDF
     */
    private byte[] convertDocxToPdf(byte[] docxBytes) throws Exception {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             InputStream is = new ByteArrayInputStream(docxBytes)) {
            
            // 使用docx4j加载DOCX
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(is);
            
            // 配置转换设置
            FOSettings foSettings = Docx4J.createFOSettings();
            foSettings.setWmlPackage(wordMLPackage);
            
            // 将DOCX转换为PDF
            Docx4J.toFO(foSettings, baos, Docx4J.FLAG_EXPORT_PREFER_XSL);
            
            return baos.toByteArray();
        }
    }
    
    /**
     * 解析Word文档为HTML
     */
    @Override
    public String parseWordToHtml(MultipartFile file) throws Exception {
        try (InputStream input = file.getInputStream()) {
            // 检查Word文档类型 (.doc 或 .docx)
            boolean isDocx = file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".docx");
            
            // 构建HTML内容
            StringBuilder htmlBuilder = new StringBuilder();
            htmlBuilder.append("<div class='word-content'>");
            
            if (isDocx) {
                // DOCX格式 (Word 2007+)
                XWPFDocument document = new XWPFDocument(input);
            
            // 处理段落
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                String text = paragraph.getText();
                if (text != null && !text.isEmpty()) {
                        String style = "";
                        // 处理基础样式
                        if (paragraph.getAlignment() != null) {
                            switch (paragraph.getAlignment()) {
                                case CENTER:
                                    style += "text-align:center;";
                                    break;
                                case RIGHT:
                                    style += "text-align:right;";
                                    break;
                                case BOTH:
                                    style += "text-align:justify;";
                                    break;
                            }
                        }
                        
                        htmlBuilder.append("<p style='").append(style).append("'>");
                        
                        // 处理段落内的样式运行
                        for (org.apache.poi.xwpf.usermodel.XWPFRun run : paragraph.getRuns()) {
                            String runText = run.getText(0);
                            if (runText != null) {
                                String runStyle = "";
                                if (run.isBold()) runStyle += "font-weight:bold;";
                                if (run.isItalic()) runStyle += "font-style:italic;";
                                if (run.isStrikeThrough()) runStyle += "text-decoration:line-through;";
                                if (run.getUnderline() != UnderlinePatterns.NONE) runStyle += "text-decoration:underline;";
                                if (run.getColor() != null) runStyle += "color:#" + run.getColor() + ";";
                                if (run.getFontSize() > 0) runStyle += "font-size:" + run.getFontSize() + "pt;";
                                if (run.getFontFamily() != null) runStyle += "font-family:'" + run.getFontFamily() + "';";
                                
                                if (!runStyle.isEmpty()) {
                                    htmlBuilder.append("<span style='").append(runStyle).append("'>");
                                    htmlBuilder.append(StringEscapeUtils.escapeHtml4(runText));
                                    htmlBuilder.append("</span>");
                                } else {
                                    htmlBuilder.append(StringEscapeUtils.escapeHtml4(runText));
                                }
                            }
                        }
                        
                        htmlBuilder.append("</p>\n");
                }
            }
            
            // 处理表格
            for (XWPFTable table : document.getTables()) {
                    htmlBuilder.append("<table border='1' style='border-collapse:collapse; width:100%;'>\n");
                    
                for (XWPFTableRow row : table.getRows()) {
                    htmlBuilder.append("<tr>\n");
                        
                    for (XWPFTableCell cell : row.getTableCells()) {
                            htmlBuilder.append("<td");
                            
                            // 处理单元格样式
                            String cellStyle = "";
                            if (cell.getWidth() > 0) cellStyle += "width:" + cell.getWidth() + "pt;";
                            
                            // 处理背景颜色
                            org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr tcPr = cell.getCTTc().getTcPr();
                            if (tcPr != null && tcPr.isSetShd() && tcPr.getShd().isSetFill()) {
                                String fillColor = tcPr.getShd().xgetFill().getStringValue();
                                if (fillColor != null && !fillColor.isEmpty() && !fillColor.equals("auto")) {
                                    cellStyle += "background-color:#" + fillColor + ";";
                                }
                            }
                            
                            if (!cellStyle.isEmpty()) {
                                htmlBuilder.append(" style='").append(cellStyle).append("'");
                            }
                            
                            htmlBuilder.append(">");
                            
                            // 处理单元格文本
                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
                                String text = paragraph.getText();
                                if (text != null && !text.isEmpty()) {
                                    htmlBuilder.append("<p>").append(StringEscapeUtils.escapeHtml4(text)).append("</p>");
                        }
                            }
                            
                        htmlBuilder.append("</td>\n");
                    }
                        
                    htmlBuilder.append("</tr>\n");
                }
                    
                htmlBuilder.append("</table>\n");
                }
                
                // 处理图片
                // 注意：需要保存图片并返回URL
                for (XWPFPictureData picture : document.getAllPictures()) {
                    // 生成唯一文件名
                    String uniqueFileName = UUID.randomUUID().toString();
                    String extension = picture.suggestFileExtension();
                    String fileName = uniqueFileName + "." + extension;
                    
                    // 保存图片
                    try {
                        String uploadDir = getUploadDir() + "images/";
                        File dir = new File(uploadDir);
                        if (!dir.exists()) {
                            dir.mkdirs();
                        }
                        
                        String filePath = uploadDir + fileName;
                        try (FileOutputStream fos = new FileOutputStream(filePath)) {
                            fos.write(picture.getData());
                        }
                        
                        // 添加图片标签
                        htmlBuilder.append("<div style='text-align:center;'>");
                        htmlBuilder.append("<img src='/uploads/images/").append(fileName).append("' ");
                        htmlBuilder.append("alt='Image' style='max-width:100%;'>");
                        htmlBuilder.append("</div>\n");
                    } catch (Exception e) {
                        log.error("保存Word文档图片失败", e);
                    }
                }
            } else {
                // 老式DOC格式 (Word 97-2003)
                // 简化处理，提示用户
                htmlBuilder.append("<p>您上传的是Word 97-2003格式(.doc)文档，为获得更好的转换效果，建议您保存为.docx格式后重新上传。</p>");
                
                // 如果后续需要更好地支持DOC格式，可以使用POI HWPF库
                try {
                    org.apache.poi.hwpf.HWPFDocument document = new org.apache.poi.hwpf.HWPFDocument(input);
                    htmlBuilder.append("<div class='doc-content'>");
                    htmlBuilder.append(document.getText());
                    htmlBuilder.append("</div>");
                } catch (Exception e) {
                    log.error("解析DOC文档失败", e);
                    htmlBuilder.append("<p>无法解析此DOC文档，请转换为DOCX格式后重试。</p>");
                }
            }
            
            htmlBuilder.append("</div>");
            return htmlBuilder.toString();
        } catch (Exception e) {
            log.error("Word文档解析失败", e);
            throw e;
        }
    }
    
    /**
     * 解析Excel文档为HTML
     */
    @Override
    public String parseExcelToHtml(MultipartFile file) throws Exception {
        // 构建HTML内容
        StringBuilder htmlBuilder = new StringBuilder();
        htmlBuilder.append("<div class='excel-content'>");
        
        try (InputStream input = file.getInputStream()) {
            // 检查文件类型 (.xls 或 .xlsx)
            boolean isXlsx = file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".xlsx");
            
            // 根据Excel类型创建工作簿
            org.apache.poi.ss.usermodel.Workbook workbook;
            if (isXlsx) {
                workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(input);
            } else {
                workbook = new org.apache.poi.hssf.usermodel.HSSFWorkbook(input);
            }
            
            // 处理所有工作表
            int sheetCount = workbook.getNumberOfSheets();
            for (int s = 0; s < sheetCount; s++) {
                org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(s);
                String sheetName = sheet.getSheetName();
                
                htmlBuilder.append("<h3>").append(StringEscapeUtils.escapeHtml4(sheetName)).append("</h3>");
                htmlBuilder.append("<table border='1' style='border-collapse:collapse; width:100%;'>\n");
                
                // 处理行
                int firstRow = sheet.getFirstRowNum();
                int lastRow = sheet.getLastRowNum();
                
                for (int rowNum = firstRow; rowNum <= lastRow; rowNum++) {
                    org.apache.poi.ss.usermodel.Row row = sheet.getRow(rowNum);
                    if (row == null) continue;
                    
                    htmlBuilder.append("<tr>\n");
                    
                    int firstCell = row.getFirstCellNum();
                    int lastCell = row.getLastCellNum();
                    
                    for (int cellNum = firstCell; cellNum < lastCell; cellNum++) {
                        org.apache.poi.ss.usermodel.Cell cell = row.getCell(cellNum);
                        String cellValue = "";
                        
                        if (cell != null) {
                            // 处理不同类型的单元格值
                            switch (cell.getCellType()) {
                                case STRING:
                                    cellValue = cell.getStringCellValue();
                                    break;
                                case NUMERIC:
                                    if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                                        cellValue = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
                                    } else {
                                        cellValue = String.valueOf(cell.getNumericCellValue());
                                    }
                                    break;
                                case BOOLEAN:
                                    cellValue = String.valueOf(cell.getBooleanCellValue());
                                    break;
                                case FORMULA:
                                    try {
                                        cellValue = String.valueOf(cell.getNumericCellValue());
                                    } catch (Exception e) {
                                        try {
                                            cellValue = cell.getStringCellValue();
                                        } catch (Exception ex) {
                                            cellValue = cell.getCellFormula();
                                        }
                                    }
                                    break;
                                default:
                                    cellValue = "";
                            }
                        }
                        
                        htmlBuilder.append("<td>").append(StringEscapeUtils.escapeHtml4(cellValue)).append("</td>\n");
                    }
                    
                    htmlBuilder.append("</tr>\n");
        }
        
        htmlBuilder.append("</table>\n");
                htmlBuilder.append("<br/>\n");
            }
            
            workbook.close();
        } catch (Exception e) {
            log.error("Excel文档解析失败", e);
            htmlBuilder.append("<p>无法解析此Excel文档: ").append(e.getMessage()).append("</p>");
        }
        
        htmlBuilder.append("</div>");
        return htmlBuilder.toString();
    }
    
    /**
     * 解析PowerPoint文档为HTML
     */
    @Override
    public String parsePptToHtml(MultipartFile file) throws Exception {
        // 构建HTML内容
        StringBuilder htmlBuilder = new StringBuilder();
        htmlBuilder.append("<div class='ppt-content'>");
        
        try (InputStream input = file.getInputStream()) {
            // 检查文件类型 (.ppt 或 .pptx)
            boolean isPptx = file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".pptx");
            
            if (isPptx) {
                // 处理PPTX格式 (PowerPoint 2007+)
                org.apache.poi.xslf.usermodel.XMLSlideShow ppt = new org.apache.poi.xslf.usermodel.XMLSlideShow(input);
                
                // 获取所有幻灯片
                List<org.apache.poi.xslf.usermodel.XSLFSlide> slides = ppt.getSlides();
                
                // 处理每张幻灯片
                for (int i = 0; i < slides.size(); i++) {
                    org.apache.poi.xslf.usermodel.XSLFSlide slide = slides.get(i);
                    
                    // 创建幻灯片容器
                    htmlBuilder.append("<div class='slide' style='border:1px solid #ddd; margin-bottom:20px; padding:20px;'>");
                    htmlBuilder.append("<h3>幻灯片 ").append(i + 1).append("</h3>");
                    
                    // 处理幻灯片标题
                    String title = "";
                    for (org.apache.poi.xslf.usermodel.XSLFShape shape : slide.getShapes()) {
                        if (shape instanceof org.apache.poi.xslf.usermodel.XSLFTextShape) {
                            org.apache.poi.xslf.usermodel.XSLFTextShape textShape = (org.apache.poi.xslf.usermodel.XSLFTextShape) shape;
                            
                            // 检查是否是标题框 (改为安全的检查方法)
                            String shapeType = textShape.getShapeType().toString();
                            if (shapeType != null && shapeType.contains("TITLE")) {
                                title = textShape.getText();
                                htmlBuilder.append("<h4>").append(StringEscapeUtils.escapeHtml4(title)).append("</h4>");
                            } else {
                                // 处理其他文本框
                                String text = textShape.getText();
                                if (text != null && !text.trim().isEmpty()) {
                                    htmlBuilder.append("<p>").append(StringEscapeUtils.escapeHtml4(text).replace("\n", "<br>")).append("</p>");
                                }
                            }
                        }
                    }
                    
                    // 处理幻灯片缩略图
                    try {
                        // 为幻灯片创建缩略图
                        java.awt.Dimension pgsize = ppt.getPageSize();
                        java.awt.image.BufferedImage img = new java.awt.image.BufferedImage(pgsize.width, pgsize.height, java.awt.image.BufferedImage.TYPE_INT_RGB);
                        java.awt.Graphics2D graphics = img.createGraphics();
                        
                        // 填充背景
                        graphics.setPaint(java.awt.Color.WHITE);
                        graphics.fill(new java.awt.Rectangle(0, 0, pgsize.width, pgsize.height));
                        
                        // 渲染幻灯片
                        slide.draw(graphics);
                        
                        // 保存图片
                        String uniqueFileName = UUID.randomUUID().toString() + ".png";
                        String uploadDir = getUploadDir() + "images/";
                        File dir = new File(uploadDir);
                        if (!dir.exists()) {
                            dir.mkdirs();
                        }
                        
                        String filePath = uploadDir + uniqueFileName;
                        javax.imageio.ImageIO.write(img, "png", new File(filePath));
                        
                        // 添加图片标签
                        htmlBuilder.append("<div style='text-align:center;'>");
                        htmlBuilder.append("<img src='/uploads/images/").append(uniqueFileName).append("' ");
                        htmlBuilder.append("alt='Slide ").append(i + 1).append("' style='max-width:100%;'>");
                        htmlBuilder.append("</div>\n");
                        
                        graphics.dispose();
                    } catch (Exception e) {
                        log.error("生成PPT幻灯片缩略图失败", e);
                    }
                    
                    htmlBuilder.append("</div>");
                }
                
                ppt.close();
            } else {
                // 简单处理老格式PPT 
                htmlBuilder.append("<p>您上传的是PowerPoint 97-2003格式(.ppt)文档，为获得更好的转换效果，建议您保存为.pptx格式后重新上传。</p>");
            }
        } catch (Exception e) {
            log.error("PowerPoint文档解析失败", e);
            htmlBuilder.append("<p>无法解析此PowerPoint文档: ").append(e.getMessage()).append("</p>");
        }
        
        htmlBuilder.append("</div>");
        return htmlBuilder.toString();
    }
    
    /**
     * 解析PDF文档为HTML
     */
    @Override
    public String parsePdfToHtml(MultipartFile file) throws Exception {
        // 构建HTML内容
        StringBuilder htmlBuilder = new StringBuilder();
        htmlBuilder.append("<div class='pdf-content'>");
        
        try (InputStream input = file.getInputStream()) {
            // 使用PDF Box解析PDF
            org.apache.pdfbox.pdmodel.PDDocument document = org.apache.pdfbox.pdmodel.PDDocument.load(input);
            
            // 创建PDF渲染器
            org.apache.pdfbox.rendering.PDFRenderer pdfRenderer = new org.apache.pdfbox.rendering.PDFRenderer(document);
            
            // 获取页数
            int pageCount = document.getNumberOfPages();
            htmlBuilder.append("<h3>PDF文档 (").append(pageCount).append(" 页)</h3>");
            
            // 处理文本内容
            org.apache.pdfbox.text.PDFTextStripper stripper = new org.apache.pdfbox.text.PDFTextStripper();
            
            // 循环处理每一页
            for (int i = 0; i < pageCount && i < 10; i++) {  // 限制最多处理10页，避免大文件
                stripper.setStartPage(i + 1);
                stripper.setEndPage(i + 1);
                String text = stripper.getText(document);
                
                htmlBuilder.append("<div class='pdf-page' style='border:1px solid #ddd; margin-bottom:20px; padding:20px;'>");
                htmlBuilder.append("<h4>第 ").append(i + 1).append(" 页</h4>");
                
                // 生成页面图像
                try {
                    java.awt.image.BufferedImage image = pdfRenderer.renderImageWithDPI(i, 150); // 150 DPI
                    
                    // 保存图片
                    String uniqueFileName = UUID.randomUUID().toString() + ".png";
                    String uploadDir = getUploadDir() + "images/";
                    File dir = new File(uploadDir);
                    if (!dir.exists()) {
                        dir.mkdirs();
                    }
                    
                    String filePath = uploadDir + uniqueFileName;
                    javax.imageio.ImageIO.write(image, "png", new File(filePath));
                    
                    // 添加图片标签
                    htmlBuilder.append("<div style='text-align:center;'>");
                    htmlBuilder.append("<img src='/uploads/images/").append(uniqueFileName).append("' ");
                    htmlBuilder.append("alt='PDF Page ").append(i + 1).append("' style='max-width:100%;'>");
                    htmlBuilder.append("</div>\n");
                } catch (Exception e) {
                    log.error("生成PDF页面图像失败", e);
                    
                    // 如果图像生成失败，显示文本内容
                    htmlBuilder.append("<pre style='white-space:pre-wrap;'>").append(StringEscapeUtils.escapeHtml4(text)).append("</pre>");
                }
                
                htmlBuilder.append("</div>");
            }
            
            if (pageCount > 10) {
                htmlBuilder.append("<p>注：此PDF文档共有 ").append(pageCount).append(" 页，为提高性能，仅显示前10页。</p>");
            }
            
            document.close();
        } catch (Exception e) {
            log.error("PDF文档解析失败", e);
            htmlBuilder.append("<p>无法解析此PDF文档: ").append(e.getMessage()).append("</p>");
        }
        
        htmlBuilder.append("</div>");
        return htmlBuilder.toString();
    }

    @Override
    public String previewDocxAsHtml(Long templateId) throws Exception {
        CertificateTemplate template = templateMapper.selectCertificateTemplateById(templateId);
        if (template == null) {
            throw new RuntimeException("模板不存在, ID: " + templateId);
        }
        if (!"DOCX".equals(template.getTemplateFormat())) {
            throw new RuntimeException("模板格式不是DOCX, ID: " + templateId);
        }
        if (StringUtils.isEmpty(template.getTemplateFileUrl())) {
            throw new RuntimeException("DOCX模板文件URL未配置, ID: " + templateId);
        }

        String filePath = getUploadDir() + template.getTemplateFileUrl();
        Path path = Paths.get(filePath);
        if (!Files.exists(path)) {
            throw new RuntimeException("模板文件不存在: " + filePath);
        }

        // 将物理文件包装成MultipartFile对象，或者修改parseWordToHtml接受路径/字节数组
        // 这里我们模拟一个MultipartFile，更佳实践是重构parseWordToHtml
        byte[] fileContent = Files.readAllBytes(path);
        MultipartFile multipartFile = new MockMultipartFile(
                template.getTemplateFileUrl(), // filename
                template.getTemplateFileUrl(), // originalFilename
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // contentType
                new ByteArrayInputStream(fileContent) // content
        );
        
        return parseWordToHtml(multipartFile);
    }

    @Override
    @Transactional
    public AjaxResult replaceDocxTemplate(Long templateId, MultipartFile file) throws IOException {
        CertificateTemplate template = templateMapper.selectCertificateTemplateById(templateId);
        if (template == null) {
            return AjaxResult.error("模板不存在, ID: " + templateId);
        }
        if (!"DOCX".equals(template.getTemplateFormat())) {
            return AjaxResult.error("只能替换DOCX格式的模板文件, 当前模板格式: " + template.getTemplateFormat());
        }

        // 检查文件大小 (例如10MB)
        long maxSize = 10 * 1024 * 1024;
        if (file.getSize() > maxSize) {
            return AjaxResult.error("上传文件大小不能超过 " + (maxSize / 1024 / 1024) + "MB");
        }

        // 文件保存逻辑
        String oldFileUrl = template.getTemplateFileUrl();
        String originalFilename = file.getOriginalFilename();
        
        // 使用RuoYiConfig.getProfile()作为基础上传目录，并加上模块特定的子目录
        String baseUploadDir = RuoYiConfig.getProfile(); 
        String templateSubDir = "/certificate_templates/"; // 自定义子目录
        
        // 打印当前配置路径
        log.info("基础上传目录: {}", baseUploadDir);
        log.info("模板子目录: {}", templateSubDir);
        
        File uploadDirFile = new File(baseUploadDir + templateSubDir);
        
        // 确保目录存在
        if (!uploadDirFile.exists()) {
            boolean dirCreated = uploadDirFile.mkdirs();
            log.info("创建目录 {} 结果: {}", uploadDirFile.getAbsolutePath(), dirCreated);
        }
        
        // 确保文件大小正常
        log.info("上传文件 {} 大小: {} 字节", originalFilename, file.getSize());
        if (file.getSize() == 0) {
            return AjaxResult.error("上传文件大小为0，请检查文件是否有效。");
        }
        
        // 使用UUID生成文件名避免冲突，确保唯一性
        String newFileName = UUID.randomUUID().toString() + "_" + originalFilename.replaceAll("[^a-zA-Z0-9._-]", "");
        // 保存相对路径 (不带前导斜杠)，确保一致性
        String newFilePath = templateSubDir.substring(1) + newFileName; // 存储为 "certificate_templates/uuid_filename.docx"
        String fullPath = baseUploadDir + templateSubDir + newFileName; // 完整路径用于文件操作
        
        log.info("准备保存文件到: {}", fullPath);
        log.info("数据库将保存路径: {}", newFilePath);
        
        File dest = new File(fullPath);

        try {
            // 使用更可靠的方式保存文件
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            
            // 读取文件到内存并写入磁盘
            byte[] fileContent = file.getBytes();
            log.info("文件内容读取完成，大小: {} 字节", fileContent.length);
            
            // 使用Java NIO写入文件
            java.nio.file.Files.write(dest.toPath(), fileContent);
            
            // 验证文件已正确写入
            if (!dest.exists() || dest.length() == 0) {
                log.error("文件写入失败或文件为空: {}", fullPath);
                return AjaxResult.error("文件保存失败，请重试");
            }
            
            log.info("文件成功保存到: {}, 文件大小: {} 字节", fullPath, dest.length());
            
            // 更新数据库
            template.setTemplateFileUrl(newFilePath); // 存储相对路径，不带前导斜杠
            template.setVersion((template.getVersion() == null ? 0 : template.getVersion()) + 1); // 版本号+1
            template.setUpdateTime(DateUtils.getNowDate());
            
            int rows = templateMapper.updateCertificateTemplate(template);
            log.info("更新数据库记录结果: {}", rows > 0 ? "成功" : "失败");

            // （可选）删除旧文件，如果oldFileUrl有效且不是新文件
            if (StringUtils.isNotEmpty(oldFileUrl) && !oldFileUrl.equals(newFilePath)) {
                try {
                    // 处理可能的路径格式差异
                    String oldFullPath = baseUploadDir + (oldFileUrl.startsWith("/") ? "" : "/") + oldFileUrl;
                    File oldDest = new File(oldFullPath);
                    if (oldDest.exists() && oldDest.isFile()) {
                        boolean deleted = oldDest.delete();
                        log.info("删除旧文件 {} 结果: {}", oldDest.getAbsolutePath(), deleted);
                    }
                } catch (Exception ex) {
                    log.warn("删除旧文件时出错: {}", ex.getMessage());
                }
            }
            
            Map<String, Object> resultData = new java.util.HashMap<>();
            resultData.put("templateFileUrl", newFilePath); // 返回新的相对URL
            resultData.put("version", template.getVersion());
            
            return AjaxResult.success("DOCX模板替换成功", resultData);
        } catch (Exception e) {
            log.error("保存文件失败: {}", fullPath, e);
            // 清理可能部分写入的文件
            if (dest.exists()) {
                dest.delete();
            }
            return AjaxResult.error("文件保存失败: " + e.getMessage());
        }
    }

    @Override
    public byte[] getTemplateFileContent(String filePath) throws IOException {
        log.info("获取文件内容: {}", filePath);
        
        // 创建文件对象
        java.io.File file = new java.io.File(filePath);
        
        // 检查文件是否存在且是文件
        if (!file.exists() || !file.isFile()) {
            log.error("文件不存在或不是文件: {}", filePath);
            return null;
        }
        
        // 检查文件大小
        if (file.length() == 0) {
            log.error("文件大小为0: {}", filePath);
            return null;
        }
        
        log.info("文件存在，大小: {} 字节", file.length());
        
        // 读取文件内容
        try {
            byte[] content = java.nio.file.Files.readAllBytes(file.toPath());
            log.info("成功读取文件内容，大小: {} 字节", content.length);
            return content;
        } catch (IOException e) {
            log.error("读取文件内容失败: {}", e.getMessage(), e);
            throw e;
        }
    }
}

// 如果未引入spring-test，可以在此处或单独文件中定义MockMultipartFile
// 为了简单起见，我将在此处添加一个基本的实现。在生产项目中，推荐使用spring-test依赖中的版本。
class MockMultipartFile implements MultipartFile {
    private final String name;
    private final String originalFilename;
    private final String contentType;
    private final byte[] content;

    public MockMultipartFile(String name, String originalFilename, String contentType, InputStream contentStream) throws IOException {
        this.name = name;
        this.originalFilename = originalFilename;
        this.contentType = contentType;
        this.content = IOUtils.toByteArray(contentStream);
    }
    public MockMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
        this.name = name;
        this.originalFilename = originalFilename;
        this.contentType = contentType;
        this.content = content;
    }

    @Override public String getName() { return name; }
    @Override public String getOriginalFilename() { return originalFilename; }
    @Override public String getContentType() { return contentType; }
    @Override public boolean isEmpty() { return content == null || content.length == 0; }
    @Override public long getSize() { return content.length; }
    @Override public byte[] getBytes() throws IOException { return content; }
    @Override public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(content); }
    @Override public void transferTo(File dest) throws IOException, IllegalStateException { 
        org.apache.commons.io.FileUtils.writeByteArrayToFile(dest, content); 
    }
} 